package oauth

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/yaoapp/yao/openapi/oauth/types"
	"github.com/yaoapp/yao/share"
)

// SigningCertificates holds the loaded signing certificates and keys
type SigningCertificates struct {
	// Primary signing certificate and private key
	SigningCert    *x509.Certificate `json:"-"`
	SigningKey     interface{}       `json:"-"` // *rsa.PrivateKey, *ecdsa.PrivateKey, etc.
	SigningKeyPair *tls.Certificate  `json:"-"`

	// Verification certificates for token validation
	VerificationCerts []*x509.Certificate `json:"-"`

	// mTLS CA certificate for client validation
	MTLSClientCACert *x509.Certificate `json:"-"`

	// Signing algorithm
	Algorithm string `json:"algorithm"`

	// Certificate paths for reference
	SigningCertPath string `json:"signing_cert_path"`
	SigningKeyPath  string `json:"signing_key_path"`

	// Auto-generated flag
	IsAutoGenerated bool `json:"is_auto_generated"`
}

// LoadSigningCertificates loads or generates signing certificates based on configuration
func LoadSigningCertificates(config *types.SigningConfig) (*SigningCertificates, error) {
	certs := &SigningCertificates{
		Algorithm: config.SigningAlgorithm,
	}

	// Check if certificate files exist
	signingCertExists := fileExists(config.SigningCertPath)
	signingKeyExists := fileExists(config.SigningKeyPath)

	// If both files exist, try to load them
	if signingCertExists && signingKeyExists {
		err := loadExistingCertificates(certs, config)
		if err != nil {
			// If loading fails, log warning and generate new certificates
			fmt.Printf("Warning: Failed to load existing certificates (%v), generating new temporary certificates\n", err)
			return generateTemporaryCertificates(config)
		}
		return certs, nil
	}

	// If certificates don't exist, generate temporary ones
	return generateTemporaryCertificates(config)
}

// loadExistingCertificates loads certificates from the configured paths
func loadExistingCertificates(certs *SigningCertificates, config *types.SigningConfig) error {
	// Load signing certificate
	certPEM, err := os.ReadFile(config.SigningCertPath)
	if err != nil {
		return fmt.Errorf("failed to read signing certificate: %w", err)
	}

	certBlock, _ := pem.Decode(certPEM)
	if certBlock == nil {
		return fmt.Errorf("failed to decode signing certificate PEM")
	}

	signingCert, err := x509.ParseCertificate(certBlock.Bytes)
	if err != nil {
		return fmt.Errorf("failed to parse signing certificate: %w", err)
	}

	// Load signing key
	keyPEM, err := os.ReadFile(config.SigningKeyPath)
	if err != nil {
		return fmt.Errorf("failed to read signing key: %w", err)
	}

	keyBlock, _ := pem.Decode(keyPEM)
	if keyBlock == nil {
		return fmt.Errorf("failed to decode signing key PEM")
	}

	var signingKey interface{}
	if config.SigningKeyPassword != "" {
		// Decrypt encrypted key
		keyBytes, err := x509.DecryptPEMBlock(keyBlock, []byte(config.SigningKeyPassword))
		if err != nil {
			return fmt.Errorf("failed to decrypt signing key: %w", err)
		}
		signingKey, err = parsePrivateKey(keyBytes)
		if err != nil {
			return fmt.Errorf("failed to parse decrypted signing key: %w", err)
		}
	} else {
		// Parse unencrypted key
		var err error
		signingKey, err = parsePrivateKey(keyBlock.Bytes)
		if err != nil {
			return fmt.Errorf("failed to parse signing key: %w", err)
		}
	}

	// Create TLS certificate pair
	keyPair, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return fmt.Errorf("failed to create key pair: %w", err)
	}

	certs.SigningCert = signingCert
	certs.SigningKey = signingKey
	certs.SigningKeyPair = &keyPair
	certs.SigningCertPath = config.SigningCertPath
	certs.SigningKeyPath = config.SigningKeyPath
	certs.IsAutoGenerated = false

	// Load verification certificates if configured
	if len(config.VerificationCerts) > 0 {
		verificationCerts, err := loadVerificationCertificates(config.VerificationCerts)
		if err != nil {
			return fmt.Errorf("failed to load verification certificates: %w", err)
		}
		certs.VerificationCerts = verificationCerts
	}

	// Load mTLS CA certificate if configured
	if config.MTLSClientCACertPath != "" {
		mtlsCACert, err := loadCertificateFromFile(config.MTLSClientCACertPath)
		if err != nil {
			return fmt.Errorf("failed to load mTLS CA certificate: %w", err)
		}
		certs.MTLSClientCACert = mtlsCACert
	}

	return nil
}

// generateTemporaryCertificates generates temporary self-signed certificates
func generateTemporaryCertificates(config *types.SigningConfig) (*SigningCertificates, error) {
	// Generate RSA private key
	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return nil, fmt.Errorf("failed to generate private key: %w", err)
	}

	// Create certificate template
	template := x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			Organization:  []string{share.App.Name},
			Country:       []string{"US"},
			Province:      []string{""},
			Locality:      []string{""},
			StreetAddress: []string{""},
			PostalCode:    []string{""},
			CommonName:    fmt.Sprintf("%s OAuth Signing Certificate", share.App.Name),
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(365 * 24 * time.Hour), // Valid for 1 year
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
	}

	// Generate certificate
	certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
	if err != nil {
		return nil, fmt.Errorf("failed to create certificate: %w", err)
	}

	// Parse the generated certificate
	cert, err := x509.ParseCertificate(certDER)
	if err != nil {
		return nil, fmt.Errorf("failed to parse generated certificate: %w", err)
	}

	// Create PEM blocks
	certPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: certDER,
	})

	keyDER, err := x509.MarshalPKCS8PrivateKey(privateKey)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal private key: %w", err)
	}

	keyPEM := pem.EncodeToMemory(&pem.Block{
		Type:  "PRIVATE KEY",
		Bytes: keyDER,
	})

	// Create TLS certificate pair
	keyPair, err := tls.X509KeyPair(certPEM, keyPEM)
	if err != nil {
		return nil, fmt.Errorf("failed to create key pair: %w", err)
	}

	// Determine system directory for storing temporary certificates
	systemDir := getSystemCertificateDirectory()

	// Create directory if it doesn't exist
	if err := os.MkdirAll(systemDir, 0755); err != nil {
		return nil, fmt.Errorf("failed to create system certificate directory: %w", err)
	}

	// Generate unique filenames
	timestamp := time.Now().Format("20060102150405")
	certPath := filepath.Join(systemDir, fmt.Sprintf("oauth_signing_cert_%s.pem", timestamp))
	keyPath := filepath.Join(systemDir, fmt.Sprintf("oauth_signing_key_%s.pem", timestamp))

	// Save certificate and key to system directory
	if err := os.WriteFile(certPath, certPEM, 0644); err != nil {
		return nil, fmt.Errorf("failed to write certificate file: %w", err)
	}

	if err := os.WriteFile(keyPath, keyPEM, 0600); err != nil {
		return nil, fmt.Errorf("failed to write key file: %w", err)
	}

	fmt.Printf("Generated temporary OAuth signing certificate at: %s\n", certPath)
	fmt.Printf("Generated temporary OAuth signing key at: %s\n", keyPath)

	return &SigningCertificates{
		SigningCert:     cert,
		SigningKey:      privateKey,
		SigningKeyPair:  &keyPair,
		Algorithm:       config.SigningAlgorithm,
		SigningCertPath: certPath,
		SigningKeyPath:  keyPath,
		IsAutoGenerated: true,
	}, nil
}

// loadVerificationCertificates loads additional verification certificates
func loadVerificationCertificates(certPaths []string) ([]*x509.Certificate, error) {
	var certs []*x509.Certificate

	for _, certPath := range certPaths {
		cert, err := loadCertificateFromFile(certPath)
		if err != nil {
			return nil, fmt.Errorf("failed to load verification certificate %s: %w", certPath, err)
		}
		certs = append(certs, cert)
	}

	return certs, nil
}

// loadCertificateFromFile loads a certificate from a PEM file
func loadCertificateFromFile(certPath string) (*x509.Certificate, error) {
	certPEM, err := os.ReadFile(certPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read certificate file: %w", err)
	}

	certBlock, _ := pem.Decode(certPEM)
	if certBlock == nil {
		return nil, fmt.Errorf("failed to decode certificate PEM")
	}

	cert, err := x509.ParseCertificate(certBlock.Bytes)
	if err != nil {
		return nil, fmt.Errorf("failed to parse certificate: %w", err)
	}

	return cert, nil
}

// parsePrivateKey parses a private key from DER bytes
func parsePrivateKey(der []byte) (interface{}, error) {
	// Try PKCS#8 first
	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
		return key, nil
	}

	// Try PKCS#1 RSA
	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
		return key, nil
	}

	// Try EC private key
	if key, err := x509.ParseECPrivateKey(der); err == nil {
		return key, nil
	}

	return nil, fmt.Errorf("unable to parse private key")
}

// fileExists checks if a file exists
func fileExists(filename string) bool {
	_, err := os.Stat(filename)
	return !os.IsNotExist(err)
}

// getSystemCertificateDirectory returns the appropriate system directory for storing certificates
func getSystemCertificateDirectory() string {
	// Use different directories based on the operating system
	homeDir, err := os.UserHomeDir()
	if err != nil {
		// Fallback to temporary directory
		return filepath.Join(os.TempDir(), "yao-oauth-certs")
	}

	// Create a hidden directory in user's home
	return filepath.Join(homeDir, ".yao", "oauth", "certs")
}

// ValidateCertificate validates a certificate for OAuth signing
func (c *SigningCertificates) ValidateCertificate() error {
	if c.SigningCert == nil {
		return fmt.Errorf("signing certificate is nil")
	}

	// Check if certificate is expired
	now := time.Now()
	if now.Before(c.SigningCert.NotBefore) {
		return fmt.Errorf("signing certificate is not yet valid")
	}

	if now.After(c.SigningCert.NotAfter) {
		return fmt.Errorf("signing certificate has expired")
	}

	// Check if certificate has appropriate key usage
	if c.SigningCert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
		return fmt.Errorf("signing certificate does not have digital signature key usage")
	}

	return nil
}

// GetPublicKey returns the public key from the signing certificate
func (c *SigningCertificates) GetPublicKey() interface{} {
	if c.SigningCert == nil {
		return nil
	}
	return c.SigningCert.PublicKey
}

// GetKeyID returns a key identifier for the signing certificate
func (c *SigningCertificates) GetKeyID() string {
	if c.SigningCert == nil {
		return ""
	}

	// Use the certificate's serial number as key ID
	return c.SigningCert.SerialNumber.String()
}

// CleanupTemporaryCertificates removes auto-generated temporary certificates
func (c *SigningCertificates) CleanupTemporaryCertificates() error {
	if !c.IsAutoGenerated {
		return nil // Don't delete user-provided certificates
	}

	var errs []error

	if c.SigningCertPath != "" && fileExists(c.SigningCertPath) {
		if err := os.Remove(c.SigningCertPath); err != nil {
			errs = append(errs, fmt.Errorf("failed to remove certificate file %s: %w", c.SigningCertPath, err))
		}
	}

	if c.SigningKeyPath != "" && fileExists(c.SigningKeyPath) {
		if err := os.Remove(c.SigningKeyPath); err != nil {
			errs = append(errs, fmt.Errorf("failed to remove key file %s: %w", c.SigningKeyPath, err))
		}
	}

	if len(errs) > 0 {
		return fmt.Errorf("cleanup errors: %v", errs)
	}

	return nil
}

// Service signing certificate methods

// GetSigningCertificates returns the signing certificates for the service
func (s *Service) GetSigningCertificates() *SigningCertificates {
	return s.signingCerts
}

// GetSigningKey returns the signing private key
func (s *Service) GetSigningKey() interface{} {
	if s.signingCerts == nil {
		return nil
	}
	return s.signingCerts.SigningKey
}

// GetSigningCertificate returns the signing certificate
func (s *Service) GetSigningCertificate() interface{} {
	if s.signingCerts == nil {
		return nil
	}
	return s.signingCerts.SigningCert
}

// GetSigningAlgorithm returns the signing algorithm
func (s *Service) GetSigningAlgorithm() string {
	if s.signingCerts == nil {
		return "RS256" // default
	}
	return s.signingCerts.Algorithm
}

// GetKeyID returns the key identifier for JWT token signing
func (s *Service) GetKeyID() string {
	if s.signingCerts == nil {
		return ""
	}
	return s.signingCerts.GetKeyID()
}

// SignToken signs a token based on the configured format (jwt or opaque)
// extraClaims: optional extra claims to add to the token (e.g., team_id, tenant_id)
func (s *Service) SignToken(tokenType, clientID, scope, subject string, expiresIn int, extraClaims ...map[string]interface{}) (string, error) {
	var claims map[string]interface{}
	if len(extraClaims) > 0 {
		claims = extraClaims[0]
	}

	switch s.config.Token.AccessTokenFormat {
	case "jwt":
		return s.signJWTToken(tokenType, clientID, scope, subject, expiresIn, claims)
	case "opaque":
		return s.signOpaqueToken(tokenType, clientID, scope, subject)
	default:
		// Default to JWT if format is not specified or unknown
		return s.signJWTToken(tokenType, clientID, scope, subject, expiresIn, claims)
	}
}

// VerifyToken verifies a token based on its format and returns token claims
func (s *Service) VerifyToken(token string) (*types.TokenClaims, error) {
	// First try to verify as JWT (JWT tokens contain dots)
	if strings.Contains(token, ".") {
		return s.verifyJWTToken(token)
	}

	// Otherwise, verify as opaque token
	return s.verifyOpaqueToken(token)
}

// SignIDToken signs an ID token with specific parameters and stores it
func (s *Service) SignIDToken(clientID, scope string, expiresIn int, userdata *types.OIDCUserInfo, extraClaims ...map[string]interface{}) (string, error) {
	if s.signingCerts == nil || s.signingCerts.SigningKey == nil {
		return "", fmt.Errorf("signing certificates not initialized")
	}

	// Check if userdata and subject are provided
	if userdata == nil || userdata.Sub == "" {
		return "", fmt.Errorf("userdata or userdata.Sub is required for ID token")
	}

	tokenSubject := userdata.Sub

	now := time.Now()

	// Create OIDC ID Token claims
	idTokenClaims := &types.OIDCIDToken{
		// Required ID Token claims
		Iss: s.config.IssuerURL,
		Sub: tokenSubject,
		Aud: clientID,
		Exp: now.Add(time.Duration(expiresIn) * time.Second).Unix(),
		Iat: now.Unix(),
	}

	// Create a map for custom claims that includes both standard and user info
	claims := jwt.MapClaims{
		// Standard OIDC ID Token claims
		"iss": idTokenClaims.Iss,
		"sub": idTokenClaims.Sub,
		"aud": idTokenClaims.Aud,
		"exp": idTokenClaims.Exp,
		"iat": idTokenClaims.Iat,
		"jti": generateJTI(),
	}

	// Add extra claims if provided (e.g., team_id, tenant_id)
	if len(extraClaims) > 0 {
		for key, value := range extraClaims[0] {
			claims[key] = value
		}
	}

	// Add user information from userdata
	// Add standard OIDC user claims if they exist
	if userdata.Name != "" {
		claims["name"] = userdata.Name
	}
	if userdata.GivenName != "" {
		claims["given_name"] = userdata.GivenName
	}
	if userdata.FamilyName != "" {
		claims["family_name"] = userdata.FamilyName
	}
	if userdata.MiddleName != "" {
		claims["middle_name"] = userdata.MiddleName
	}
	if userdata.Nickname != "" {
		claims["nickname"] = userdata.Nickname
	}
	if userdata.PreferredUsername != "" {
		claims["preferred_username"] = userdata.PreferredUsername
	}
	if userdata.Profile != "" {
		claims["profile"] = userdata.Profile
	}
	if userdata.Picture != "" {
		claims["picture"] = userdata.Picture
	}
	if userdata.Website != "" {
		claims["website"] = userdata.Website
	}
	if userdata.Email != "" {
		claims["email"] = userdata.Email
	}
	if userdata.EmailVerified != nil {
		claims["email_verified"] = *userdata.EmailVerified
	}
	if userdata.Gender != "" {
		claims["gender"] = userdata.Gender
	}
	if userdata.Birthdate != "" {
		claims["birthdate"] = userdata.Birthdate
	}
	if userdata.Zoneinfo != "" {
		claims["zoneinfo"] = userdata.Zoneinfo
	}
	if userdata.Locale != "" {
		claims["locale"] = userdata.Locale
	}
	if userdata.PhoneNumber != "" {
		claims["phone_number"] = userdata.PhoneNumber
	}
	if userdata.PhoneNumberVerified != nil {
		claims["phone_number_verified"] = *userdata.PhoneNumberVerified
	}
	if userdata.Address != nil {
		claims["address"] = userdata.Address
	}
	if userdata.UpdatedAt != nil {
		claims["updated_at"] = *userdata.UpdatedAt
	}

	// Add Yao custom fields with namespace
	if userdata.YaoUserID != "" {
		claims["yao:user_id"] = userdata.YaoUserID
	}
	if userdata.YaoTenantID != "" {
		claims["yao:tenant_id"] = userdata.YaoTenantID
	}
	if userdata.YaoTeamID != "" {
		claims["yao:team_id"] = userdata.YaoTeamID
	}
	if userdata.YaoIsOwner != nil {
		claims["yao:is_owner"] = *userdata.YaoIsOwner
	}
	if userdata.YaoTypeID != "" {
		claims["yao:type_id"] = userdata.YaoTypeID
	}
	// Add Yao team info if present
	if userdata.YaoTeam != nil {
		teamMap := make(map[string]interface{})
		if userdata.YaoTeam.TeamID != "" {
			teamMap["team_id"] = userdata.YaoTeam.TeamID
		}
		if userdata.YaoTeam.Logo != "" {
			teamMap["logo"] = userdata.YaoTeam.Logo
		}
		if userdata.YaoTeam.Name != "" {
			teamMap["name"] = userdata.YaoTeam.Name
		}
		if userdata.YaoTeam.OwnerID != "" {
			teamMap["owner_id"] = userdata.YaoTeam.OwnerID
		}
		if userdata.YaoTeam.Description != "" {
			teamMap["description"] = userdata.YaoTeam.Description
		}
		if userdata.YaoTeam.UpdatedAt != nil {
			teamMap["updated_at"] = *userdata.YaoTeam.UpdatedAt
		}
		if len(teamMap) > 0 {
			claims["yao:team"] = teamMap
		}
	}
	// Add Yao member info if present (for team context)
	if userdata.YaoMember != nil {
		memberMap := make(map[string]interface{})
		if userdata.YaoMember.MemberID != "" {
			memberMap["member_id"] = userdata.YaoMember.MemberID
		}
		if userdata.YaoMember.DisplayName != "" {
			memberMap["display_name"] = userdata.YaoMember.DisplayName
		}
		if userdata.YaoMember.Bio != "" {
			memberMap["bio"] = userdata.YaoMember.Bio
		}
		if userdata.YaoMember.Avatar != "" {
			memberMap["avatar"] = userdata.YaoMember.Avatar
		}
		if userdata.YaoMember.Email != "" {
			memberMap["email"] = userdata.YaoMember.Email
		}
		if len(memberMap) > 0 {
			claims["yao:member"] = memberMap
		}
	}
	// Add Yao type info if present
	if userdata.YaoType != nil {
		typeMap := make(map[string]interface{})
		if userdata.YaoType.TypeID != "" {
			typeMap["type_id"] = userdata.YaoType.TypeID
		}
		if userdata.YaoType.Name != "" {
			typeMap["name"] = userdata.YaoType.Name
		}
		if userdata.YaoType.Locale != "" {
			typeMap["locale"] = userdata.YaoType.Locale
		}
		if len(typeMap) > 0 {
			claims["yao:type"] = typeMap
		}
	}

	// Add scope if provided (useful for determining which claims to include)
	if scope != "" {
		claims["scope"] = scope
	}

	// Create token with claims
	token := jwt.NewWithClaims(getSigningMethod(s.config.Token.AccessTokenSigningAlg), claims)

	// Set key ID in header
	token.Header["kid"] = s.GetKeyID()

	// Set token type in header
	token.Header["typ"] = "JWT"

	// Sign token with private key
	signedToken, err := token.SignedString(s.signingCerts.SigningKey)
	if err != nil {
		return "", fmt.Errorf("failed to sign ID token: %w", err)
	}

	return signedToken, nil
}

// signJWTToken signs a JWT token using the configured signing algorithm
func (s *Service) signJWTToken(tokenType, clientID, scope, subject string, expiresIn int, extraClaims map[string]interface{}) (string, error) {
	if s.signingCerts == nil || s.signingCerts.SigningKey == nil {
		return "", fmt.Errorf("signing certificates not initialized")
	}

	now := time.Now()

	// Use MapClaims to support extra claims
	claims := jwt.MapClaims{
		// Standard JWT claims
		"iss": s.config.IssuerURL,
		"sub": subject,
		"aud": clientID,
		"exp": now.Add(time.Duration(expiresIn) * time.Second).Unix(),
		"nbf": now.Unix(),
		"iat": now.Unix(),
		"jti": generateJTI(),
		// Custom OAuth claims
		"client_id":  clientID,
		"scope":      scope,
		"token_type": tokenType,
	}

	// Add extra claims if provided (e.g., team_id, tenant_id)
	for key, value := range extraClaims {
		claims[key] = value
	}

	// Create token with claims
	token := jwt.NewWithClaims(getSigningMethod(s.config.Token.AccessTokenSigningAlg), claims)

	// Set key ID in header
	token.Header["kid"] = s.GetKeyID()

	// Sign token with private key
	return token.SignedString(s.signingCerts.SigningKey)
}

// verifyJWTToken verifies a JWT token and returns its claims
func (s *Service) verifyJWTToken(tokenString string) (*types.TokenClaims, error) {
	if s.signingCerts == nil || s.signingCerts.SigningCert == nil {
		return nil, fmt.Errorf("signing certificates not initialized")
	}

	// Parse token with MapClaims to support extra claims
	token, err := jwt.ParseWithClaims(tokenString, jwt.MapClaims{}, func(token *jwt.Token) (interface{}, error) {
		// Validate signing method
		expectedMethod := getSigningMethod(s.config.Token.AccessTokenSigningAlg)
		if token.Method != expectedMethod {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}

		// Return public key for verification
		return s.signingCerts.GetPublicKey(), nil
	})

	if err != nil {
		return nil, fmt.Errorf("failed to parse JWT token: %w", err)
	}

	if !token.Valid {
		return nil, fmt.Errorf("invalid JWT token")
	}

	// Extract claims
	mapClaims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return nil, fmt.Errorf("invalid JWT claims type")
	}

	// Convert to TokenClaims
	tokenClaims := &types.TokenClaims{
		Extra: make(map[string]interface{}),
	}

	// Extract standard claims
	if sub, ok := mapClaims["sub"].(string); ok {
		tokenClaims.Subject = sub
	}
	if clientID, ok := mapClaims["client_id"].(string); ok {
		tokenClaims.ClientID = clientID
	}
	if scope, ok := mapClaims["scope"].(string); ok {
		tokenClaims.Scope = scope
	}
	if tokenType, ok := mapClaims["token_type"].(string); ok {
		tokenClaims.TokenType = tokenType
	}
	if iss, ok := mapClaims["iss"].(string); ok {
		tokenClaims.Issuer = iss
	}
	if jti, ok := mapClaims["jti"].(string); ok {
		tokenClaims.JTI = jti
	}

	// Extract time claims
	if exp, ok := mapClaims["exp"].(float64); ok {
		tokenClaims.ExpiresAt = time.Unix(int64(exp), 0)
	}
	if iat, ok := mapClaims["iat"].(float64); ok {
		tokenClaims.IssuedAt = time.Unix(int64(iat), 0)
	}

	// Extract audience
	if aud, ok := mapClaims["aud"].(string); ok {
		tokenClaims.Audience = []string{aud}
	} else if audArray, ok := mapClaims["aud"].([]interface{}); ok {
		audience := make([]string, 0, len(audArray))
		for _, a := range audArray {
			if audStr, ok := a.(string); ok {
				audience = append(audience, audStr)
			}
		}
		tokenClaims.Audience = audience
	}

	// Extract extended claims for multi-tenancy and team support
	if teamID, ok := mapClaims["team_id"].(string); ok {
		tokenClaims.TeamID = teamID
	}
	if tenantID, ok := mapClaims["tenant_id"].(string); ok {
		tokenClaims.TenantID = tenantID
	}

	// Store all extra claims for flexibility
	standardClaims := map[string]bool{
		"sub": true, "client_id": true, "scope": true, "token_type": true,
		"exp": true, "iat": true, "nbf": true, "iss": true, "aud": true, "jti": true,
		"team_id": true, "tenant_id": true,
	}
	for key, value := range mapClaims {
		if !standardClaims[key] {
			tokenClaims.Extra[key] = value
		}
	}

	return tokenClaims, nil
}

// signOpaqueToken signs an opaque token using HMAC or RSA signature
func (s *Service) signOpaqueToken(tokenType, clientID, scope, subject string) (string, error) {
	// Generate base opaque token
	baseToken, err := s.generateOpaqueTokenBase(tokenType, clientID)
	if err != nil {
		return "", fmt.Errorf("failed to generate base opaque token: %w", err)
	}

	// Create token metadata for signature
	tokenData := fmt.Sprintf("%s.%s.%s.%s.%d", baseToken, clientID, scope, subject, time.Now().Unix())

	// Sign the token data
	signature, err := s.signData([]byte(tokenData))
	if err != nil {
		return "", fmt.Errorf("failed to sign opaque token: %w", err)
	}

	// Combine base token with signature
	signedToken := fmt.Sprintf("%s.%s", baseToken, base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(signature))

	return signedToken, nil
}

// verifyOpaqueToken verifies an opaque token signature and returns token claims
func (s *Service) verifyOpaqueToken(token string) (*types.TokenClaims, error) {
	parts := strings.Split(token, ".")
	if len(parts) < 2 {
		return nil, fmt.Errorf("invalid opaque token format")
	}

	baseToken := parts[0]
	signaturePart := parts[len(parts)-1]

	// Decode signature
	signature, err := base64.URLEncoding.WithPadding(base64.NoPadding).DecodeString(signaturePart)
	if err != nil {
		return nil, fmt.Errorf("failed to decode token signature: %w", err)
	}

	// Extract token information from store
	tokenInfo, err := s.getAccessTokenData(token)
	if err != nil {
		return nil, fmt.Errorf("token not found or invalid: %w", err)
	}

	// Reconstruct token data for verification
	clientID := tokenInfo["client_id"].(string)
	scope := ""
	if scopeVal, ok := tokenInfo["scope"].(string); ok {
		scope = scopeVal
	}
	subject := ""
	if subjectVal, ok := tokenInfo["subject"].(string); ok {
		subject = subjectVal
	}
	issuedAt := tokenInfo["issued_at"].(int64)

	tokenData := fmt.Sprintf("%s.%s.%s.%s.%d", baseToken, clientID, scope, subject, issuedAt)

	// Verify signature
	if err := s.verifySignature([]byte(tokenData), signature); err != nil {
		return nil, fmt.Errorf("invalid token signature: %w", err)
	}

	// Build token claims
	tokenClaims := &types.TokenClaims{
		Subject:   subject,
		ClientID:  clientID,
		Scope:     scope,
		TokenType: "access_token",
		IssuedAt:  time.Unix(issuedAt, 0),
		Issuer:    s.config.IssuerURL,
	}

	if expiresAt, ok := tokenInfo["expires_at"].(int64); ok {
		tokenClaims.ExpiresAt = time.Unix(expiresAt, 0)
	}

	return tokenClaims, nil
}

// signData signs data using the configured signing key
func (s *Service) signData(data []byte) ([]byte, error) {
	if s.signingCerts == nil || s.signingCerts.SigningKey == nil {
		return nil, fmt.Errorf("signing key not available")
	}

	switch key := s.signingCerts.SigningKey.(type) {
	case *rsa.PrivateKey:
		// Use RSA-PSS for signing
		hash := sha256.Sum256(data)
		signature, err := rsa.SignPSS(rand.Reader, key, crypto.SHA256, hash[:], nil)
		if err != nil {
			return nil, fmt.Errorf("failed to sign with RSA key: %w", err)
		}
		return signature, nil
	default:
		return nil, fmt.Errorf("unsupported signing key type: %T", key)
	}
}

// verifySignature verifies a signature using the configured public key
func (s *Service) verifySignature(data []byte, signature []byte) error {
	if s.signingCerts == nil || s.signingCerts.SigningCert == nil {
		return fmt.Errorf("signing certificate not available")
	}

	switch pubKey := s.signingCerts.GetPublicKey().(type) {
	case *rsa.PublicKey:
		// Use RSA-PSS for verification
		hash := sha256.Sum256(data)
		err := rsa.VerifyPSS(pubKey, crypto.SHA256, hash[:], signature, nil)
		if err != nil {
			return fmt.Errorf("failed to verify RSA signature: %w", err)
		}
		return nil
	default:
		return fmt.Errorf("unsupported public key type: %T", pubKey)
	}
}

// generateOpaqueTokenBase generates the base part of an opaque token
func (s *Service) generateOpaqueTokenBase(tokenType, clientID string) (string, error) {
	// Generate random bytes for token
	randomBytes := make([]byte, 32)
	if _, err := rand.Read(randomBytes); err != nil {
		return "", fmt.Errorf("failed to generate random bytes: %w", err)
	}

	// Create base token with type, client ID, timestamp, and random component
	randomPart := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(randomBytes)
	timestamp := time.Now().Format("20060102150405")

	return fmt.Sprintf("%s_%s_%s_%s", tokenType, clientID, timestamp, randomPart), nil
}

// getSigningMethod returns the JWT signing method for the given algorithm
func getSigningMethod(algorithm string) jwt.SigningMethod {
	switch algorithm {
	case "RS256":
		return jwt.SigningMethodRS256
	case "RS384":
		return jwt.SigningMethodRS384
	case "RS512":
		return jwt.SigningMethodRS512
	case "PS256":
		return jwt.SigningMethodPS256
	case "PS384":
		return jwt.SigningMethodPS384
	case "PS512":
		return jwt.SigningMethodPS512
	default:
		return jwt.SigningMethodRS256 // Default
	}
}

// generateJTI generates a unique JWT ID
func generateJTI() string {
	randomBytes := make([]byte, 16)
	rand.Read(randomBytes)
	return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(randomBytes)
}
